#include <iostream>
#include <fstream>
#include <iomanip>

#include "../nlohmann/json.hpp"

using namespace std;
using json = nlohmann::json;

int main(int argc, char **argv)
{
    cout << "------------------ test start ------------------" << endl;
    // create an empty structure (null)
    json j;

    // add a number that is stored as double (note the implicit conversion of j to an object)
    j["pi"] = 3.141;
    // add a Boolean that is stored as bool
    j["happy"] = true;
    // add a string that is stored as std::string
    j["name"] = "Niels";
    // add another null object by passing nullptr
    j["nothing"] = nullptr;
    // add an object inside the object
    j["answer"]["everything"] = 42;
    // add an array that is stored as std::vector (using an initializer list)
    j["list"] = {1, 0, 2};
    // add another object (using an initializer list of pairs)
    j["object"] = {{"value", 42.99},
                   {"currency", "USD"}};
    // instead, you could also write (which looks very similar to the JSON above)
    json j2 = {
        {"pi", 3.141},
        {"happy", true},
        {"name", "Niels"},
        {"nothing", nullptr},
        {"answer", {{"everything", 42}}},
        {"list", {1, 0, 2}},
        {"object", {{"value", 42.99}, {"currency", "USD"}}}};

    string jsonFile = "new_tree.json";
    std::ofstream outFile(jsonFile);
    outFile << j.dump(4) << std::endl;
    outFile << setw(2) << j << std::endl;
    string jsonFile01 = "new_tree01.json";
    std::ofstream outFile01(jsonFile01);
    outFile01 << j2 << std::endl;
    outFile01 << j2.dump() << std::endl;

    outFile.close();
    outFile01.close();
    cout << "--------------------------------" << endl;

    // add "age": 12
    j2["age"]  = 12;
    cout << "--------------------------------" << endl;

    // delete "name": "Niels"
    j2.erase("name");
    cout << "--------------------------------" << endl;

    // modify
    j2["happy"] = false;
    j2.at("pi") = 3.14159;
    cout << "--------------------------------" << endl;

    // query
    std::map<std::string, int> m;
    j2.at("answer").get_to(m);
    cout << "i = " << (*m.begin()).first << endl;

    double p;
    p = j2["pi"].get<double>();
    j2["pi"].get_to(p);
    cout << "--------------------------------" << endl;

    // json 构造
    // C++ 的新特性 —— 源码转译  R"(
    json j3 = R"( 
    {
        "name": "Judd Trump",
        "credits": 1754500,
        "ranking": 1
    }
    )"_json;

    json j4{
        {"name", "Judd Trump"},
        {"credits", 1754500},
        {"ranking", 1}};

    std::cout << j3.dump(4) << std::endl;
    std::cout << j4.dump(4) << std::endl;
    cout << "--------------------------------" << endl;

    // parse
    std::string s = R"({
    "name": "Judd Trump",
    "credits": 1754500,
    "ranking": 1
})";
    auto j5 = json::parse(s);
    cout << "--------------------------------" << endl;

    // serialization
    auto s1 = j5.dump(4);
    string str = to_string(j3);
    std::cout << str << std::endl;
    cout << "--------------------------------" << endl;

    // parse form json file
    json j6;
    std::ifstream jfifstr("new_tree.json", ios::binary);
    jfifstr >> j6;
    cout << j6.dump() << endl;
    cout << to_string(j6) << endl;

    json j7 = j6.back();
    cout << j7.dump(4) << endl;
    cout << "--------------------------------" << endl;

    // create an array using push_back
    json j8;
    j8.push_back("foo");
    j8.push_back(1);
    j8.push_back(true);
    cout << j8.dump() << endl;

    // comparison
    bool x = (j8 == "[\"foo\", 1, true]"_json); // true

    // iterate the array
    for (json::iterator it = j8.begin(); it != j8.end(); ++it)
    {
        std::cout << *it << '\n';
    }

    // range-based for
    for (auto element : j8)
    {
        std::cout << element << '\n';
    }

    string str0;
    str0 = j8[0].get<string>();
    int a;
    a = j8[1].get<int>();
    j8[1].get_to(a);

    auto size = j8.size();
    auto empty = j8.empty();
    auto type = j8.type();
    j8.clear();
    cout << "--------------------------------" << endl;

    // creat a object json
    json o;
    o["foo"] = 23;
    o["bar"] = false;
    o["baz"] = 3.141;

    // find an entry
    if (o.find("foo") != o.end()) {
        cout << R"(I found "foo")" << endl;
    }

    // test string & const char*
    string temp("tempstr");
    const char* pstr = "constchar*";
    o[temp] = "like";
    o[pstr] = "ccp";

    cout << o.dump() << endl;

    cout << "--------------------------------" << endl;


    
    return 0;
}